#include <stdio.h>
#include <string.h>
#include <Includes.h>
#include <APP_Charging.h>
#include <APP_Comm.h>
#include <APP_Bill.h>
#include <DEV_Main.h>
#include <DRV_EC600S.h>
#include <DRV_EC600S_Sock.h>
#include <OPP_Debug.h>
#include <SVS_Station.h>
#include <SVS_Time.h>

#define BMSID_LENGTH    27
#define PASSWORD_LENGTH    16

#define MTU    EC600S_HEX_MAX_MTU
#define INVALID_TO    0
#define AUTO_SEQNO    0


U8 CommVer=10;
U16 HardFault=0;//硬件故障

//CRC 码表高字节
BYTE gabyCRCHi[] =
{
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
    0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,
    0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,
    0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,
    0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,
    0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,
    0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,
    0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,
    0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
    0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
    0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,
    0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,
    0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
    0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
    0x80,0x41,0x00,0xc1,0x81,0x40
} ;
//CRC 码表低字节
BYTE gabyCRCLo[] =
{
    0x00,0xc0,0xc1,0x01,0xc3,0x03,0x02,0xc2,0xc6,0x06,
    0x07,0xc7,0x05,0xc5,0xc4,0x04,0xcc,0x0c,0x0d,0xcd,
    0x0f,0xcf,0xce,0x0e,0x0a,0xca,0xcb,0x0b,0xc9,0x09,
    0x08,0xc8,0xd8,0x18,0x19,0xd9,0x1b,0xdb,0xda,0x1a,
    0x1e,0xde,0xdf,0x1f,0xdd,0x1d,0x1c,0xdc,0x14,0xd4,
    0xd5,0x15,0xd7,0x17,0x16,0xd6,0xd2,0x12,0x13,0xd3,
    0x11,0xd1,0xd0,0x10,0xf0,0x30,0x31,0xf1,0x33,0xf3,
    0xf2,0x32,0x36,0xf6,0xf7,0x37,0xf5,0x35,0x34,0xf4,
    0x3c,0xfc,0xfd,0x3d,0xff,0x3f,0x3e,0xfe,0xfa,0x3a,
    0x3b,0xfb,0x39,0xf9,0xf8,0x38,0x28,0xe8,0xe9,0x29,
    0xeb,0x2b,0x2a,0xea,0xee,0x2e,0x2f,0xef,0x2d,0xed,
    0xec,0x2c,0xe4,0x24,0x25,0xe5,0x27,0xe7,0xe6,0x26,
    0x22,0xe2,0xe3,0x23,0xe1,0x21,0x20,0xe0,0xa0,0x60,
    0x61,0xa1,0x63,0xa3,0xa2,0x62,0x66,0xa6,0xa7,0x67,
    0xa5,0x65,0x64,0xa4,0x6c,0xac,0xad,0x6d,0xaf,0x6f,
    0x6e,0xae,0xaa,0x6a,0x6b,0xab,0x69,0xa9,0xa8,0x68,
    0x78,0xb8,0xb9,0x79,0xbb,0x7b,0x7a,0xba,0xbe,0x7e,
    0x7f,0xbf,0x7d,0xbd,0xbc,0x7c,0xb4,0x74,0x75,0xb5,
    0x77,0xb7,0xb6,0x76,0x72,0xb2,0xb3,0x73,0xb1,0x71,
    0x70,0xb0,0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,
    0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9c,0x5c,
    0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,0x5a,0x9a,0x9b,0x5b,
    0x99,0x59,0x58,0x98,0x88,0x48,0x49,0x89,0x4b,0x8b,
    0x8a,0x4a,0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
    0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,
    0x43,0x83,0x41,0x81,0x80,0x40
} ;

enum EN_COMM_FSM g_enCommFsm;
int sock=0;
U16 g_usSeqNo=0;//报文流水号
U16 g_usTrnNo=0;//交易流水号自增编号


AUTH_FAIL_REASON_ST stAuthCode[]={
    {0x00,"Success"},
    {0x01,"Account does not exist"},
    {0x02,"Account freeze"},
    {0x03,"Account has not enough money"},
    {0x04,"This card has an unclaimed record"},
    {0x05,"Staion not word"},
    {0x06,"This account cannot be charged on this station"},
    {0x07,"Password error"},
    {0x08,"Staion capacity is not enough"},
    {0x09,"Vin is not exist"},
    {0x0A,"Staion has no payment record"},
    {0x0B,"This station does not support card swiping"}
};

U16 PacketFilter(U8 *buffer,U16 len)
{
    return 0;
}


U16 BillModeNumber(void)
{
    //Add Your Code Here
    return BILL_NUM_DEF;
}

enum EN_START_CHG_WAY StartChgWay(void)
{
    //Add Your Code Here
    return CHG_SWIPE_CARD_WAY;
}

int PhyCardIdGet(U8 *card_no)
{
    //Add Your Code Here
    //memcpy(card_no,PhyCardID,sizeof(PhyCardID));
    memcpy(card_no,PhyCardID.ID,PHY_CARDID_LENGTH);
    return PHY_CARDID_LENGTH;
}
int PasswordGet(U8 *password)
{
    //Add Your Code Here
    U8 pass[PASSWORD_LENGTH]={0};
    memcpy(password,pass,PASSWORD_LENGTH);
    return PASSWORD_LENGTH;
}

int VinGet(U8 *vin_code)
{
    //Add Your Code Here
    U8 vin[VIN_LENGTH]={0};
    memcpy(vin_code,vin,VIN_LENGTH);
    return VIN_LENGTH;
}

int BmsIdGet(U8 *data)
{
    //Add Your Code Here
    U8 bmsid[BMSID_LENGTH]={0};
    memcpy(data,bmsid,BMSID_LENGTH);
    return BMSID_LENGTH;
}

U8 TransactionID(void)
{
    return TRN_ID_CARD;
}

//生成交易流水号,返回值交易记录长度
U8 MakeTrnNum(__INOUT__ U8 *data, _IN_ int dlen)
{
    int len=0;
    ST_TIME time;
    
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    data[len++]=GunNum;
    TimeGet(&time);
    data[len++]=time.Year-2000;
    data[len++]=time.Month;
    data[len++]=time.Day;
    data[len++]=time.Hour;
    data[len++]=time.Min;
    data[len++]=time.Sencond;
    *(U16 *)&data[len]=g_usTrnNo++;
    len+=2;
    return len;
}
//累计充电时间，单位min
U16 AcumChgTime(void)
{
    return g_usAcumChgTime;
}
//剩余充电时间，单位min
U16 AcumRemainTime(void)
{
    return g_usAcumChgTime;
}

#warning "Abstract Function Above"
/////////////////////////////////////////////////////////////////

WORD ModbusCRC(BYTE * pData, BYTE len)
{
    BYTE byCRCHi = 0xff ;
    BYTE byCRCLo = 0xff ;
    BYTE byIdx ;
    WORD crc ;
    while(len--)
    {
        byIdx = byCRCHi ^* pData++ ;
        byCRCHi = byCRCLo ^ gabyCRCHi[byIdx] ;
        byCRCLo = gabyCRCLo[byIdx] ;
    }
    crc = byCRCHi ;
    crc <<= 8 ;
    crc += byCRCLo ;
    return crc ;
}

//标准时间转换为CP56格式时间
int Time2CP56Famat(ST_TIME *time,U8 *data, U8 dlen)
{
    int len=0;
    
    data[len++]=(time->Sencond*1000)&0x00FF;
    data[len++]=((time->Sencond*1000)&0xFF00)>>8;
    data[len++]=time->Min;
    data[len++]=time->Hour;
    data[len++]=time->Day;
    data[len++]=time->Month;
    data[len++]=time->Year-2000;
    return len;
}
//CP56格式时间转换为标准时间
int CP562TimeFamat(U8 *data, U8 dlen, ST_TIME *time)
{
    int len=0;
    
    time->Sencond=(data[len]|(data[len+1]<<8))/1000;
    len+=2;
    time->Min=data[len++]&0x3F;
    time->Hour=data[len++]&0x1F;
    time->Day=data[len++]&0x1F;
    time->Month=data[len++]&0x0F;
    time->Year=2000+(data[len++]&0x7F);
    
    return len;
}


int CommSockInit(void)
{
    EC600S_ADDR addr;
    int ret;

    sock = Ec600sSocket(OAF_INET, SOCK_TCP, 1);
    if(sock < 0)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "alloc socket err=%d\r\n",sock);
        return 1;
    }
    strcpy(addr.dstAddr,OINADDR_ANY);
    addr.port=0;
    ret=Ec600sBind(sock, &addr, sizeof(EC600S_ADDR));
    if(ret<0)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "sock:%d bind error=%d\r\n",sock,ret);
        Ec600sClose(sock);
        return 2;
    }
    strcpy(addr.dstAddr,(char *)SVR_IP);
    addr.port=SVR_PORT;
    if(Ec600sConnect(sock,(EC600S_ADDR *)&addr,sizeof(EC600S_ADDR))==-1){
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "sock:%d connect() error\n",sock);
        Ec600sClose(sock);
        return 3;
    }
    return 0;
}

int CommPacketFormatCheck(U8 *packet/*IN*/, U8 packet_len/*IN*/, U8 *cmd, U16 *seqno/*OUT*/, U8 **pdata/*OUT*/, U8 *dlen/*OUT*/)
{
    U16 crc;
    //帧头判断
    if(packet[0] != 0x68)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "hdr %02x err\r\n",packet[0]);
        return 2;
    }
    //最小长度判断
    if(packet_len < 8)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "packet_len %d err\r\n",packet_len);
        return 1;
    }
    //长度判断
    if((packet[1]+4) != packet_len)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "len1:%d != len2:%d err\r\n",(packet[1]+4),packet_len);
        return 3;
    }
    crc=ModbusCRC(&packet[2], packet[1]);
    if(crc!=OPP_NTOHS(*(U16 *)&packet[packet_len-2]))
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "crc1:%04x != crc2:%04x err\r\n",crc,OPP_NTOHS(*(U16 *)&packet[packet_len-2]));
        return 4;
    }
    //序列号
    *seqno=*(U16 *)&packet[2];
    //帧类型标识
    *cmd=packet[5];
    //不加密
    if(packet[4]==0x00)
    {
        *pdata = &packet[6];
        *dlen = packet[2]-4;
    }
    else if(packet[4]==0x01)
    {
        //解密
    }
    return 0;
}

int CommUnpackData(U8 *buffer, U8 len)
{
    int err;
    U8 *pdata,dlen,cmd;
    U16 seqno;
    int i=0;
    
    if(buffer[0] == 0x68 && (buffer[1]+4) == len)
    {
        DataDump(DEBUG_MODULE_COMM,"COMM_RCV",buffer,len);        
        err = CommPacketFormatCheck(&buffer[0],buffer[1]+4, &cmd, &seqno,&pdata,&dlen);
        if(err != 0)
        {
            return -1;
        }
    
        for(i=0;i<sizeof(CmdTbl)/sizeof(CMD_ELEMENT_ST);i++)
        {
            if(CmdTbl[i].rcmd==cmd)
            {
                if(CmdTbl[i].precv!=NULL)
                {
                    err=CmdTbl[i].precv(CmdTbl[i].cmdidx,seqno,pdata,dlen);
                    if(err==0)
                    {
                        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CMD:0x%02X SUCC\r\n",cmd);
                        CmdTbl[i].result=CMD_RSLT_SUCC;
                    }
                    else
                    {
                        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "CMD:0x%02X ERROR\r\n",cmd);
                        CmdTbl[i].result=CMD_RSLT_ERROR;
                    }
                    if(CmdTbl[i].prsp!=NULL)
                    {
                        CmdTbl[i].prsp(CmdTbl[i].cmdidx,err,seqno,pdata,dlen);
                    }
                    CmdTbl[i].code=err;
                    CmdTbl[i].rtick=OppTickCountGet();
                }
                break;
            }
        }
        if(i==sizeof(CmdTbl)/sizeof(CMD_ELEMENT_ST))
            DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "CMD:0x%02X Not process\r\n",cmd);
    }
    return 0;
}

int CommReceive(void)
{
    int rlen = 0;
    U8 buffer[MTU]={0};
    U8 *pdata;
    int idx=0;
    int len=0;
    int remain;
    
    rlen=Ec600sRecv(sock, (char *)buffer, sizeof(buffer), 0);
    if(rlen>0)
    {
        //找帧头
        for(idx=0;idx<rlen;idx++)
        {
            if(buffer[idx]==0x68)
            {
                break;
            }
        }
        //没找到
        if(idx==rlen)
            return -1;

        remain=rlen-idx;
        pdata=&buffer[idx];
        len=pdata[1]+4;
        for(;;)
        {
            if(CommUnpackData(pdata,len)!=0)
                return -2;
            remain -= len;
            pdata+=len;
            len=pdata[1]+4;
            if(remain < 9)
                return -3;
        }
    }
    return rlen;
}

int CommSend(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;
    
    buffer[len++]=0x68;
    buffer[len++]=(4+dlen);
    if(seqno==AUTO_SEQNO)
        *(U16 *)&buffer[len]=g_usSeqNo++;
    else
        *(U16 *)&buffer[len]=seqno;
    len+=2;
    buffer[len++]=0;//不加密
    buffer[len++]=CmdTbl[cmdidx].scmd;//上下行
    memcpy(&buffer[len],data,dlen);
    len+=dlen;
    *(U16 *)&buffer[len]=OPP_HTONS(ModbusCRC(&buffer[2], (4+dlen)));
    len+=2;

    if(CmdTbl[cmdidx].timeout != INVALID_TO){
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommSend cmd=%02X change to wait\r\n",CmdTbl[cmdidx].scmd);
        CmdTbl[cmdidx].result=CMD_RSLT_WAIT;
        CmdTbl[cmdidx].stick=OppTickCountGet();
    }
    
    DataDump(DEBUG_MODULE_COMM,"COMM_SEND",buffer,len);        
    return Ec600sSend(sock,(char *)buffer,len,0);
}

int CommLogin(void *para)
{
    U8 data[MTU]={0};
    int len=0;
    int err=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommLogin Send\r\n");
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    data[len++]=STAType;
    data[len++]=GunNum;
    data[len++]=CommVer;
    strncpy((char *)&data[len],"1.1.1",8);
    len+=8;
    data[len++]=0;
    //IMSI
    len+=10;
    //运营商
    data[len++]=2;//电信
    err=CommSend(LOGIN_IDX,AUTO_SEQNO,data,len);
    if(err < 0)
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_ERROR, "send err %d\r\n",err);
    }
    return err;
}

int CommLoginAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "login ack\r\n");
    //g_enCommFsm = COMM_FSM_READY;
    return 0;
}

int CommLoginErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}

int CommHeartbeat(void *para)
{
    U8 data[MTU]={0};
    int len=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "send CommHeartbeat\r\n");
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    data[len++]=1;//枪编号
    data[len++]=0;//枪状态
    
    return CommSend(HB_IDX,AUTO_SEQNO,data,len);
}

int CommHeartbeatAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommHeartbeatAck\r\n");
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "GunNo:%0d\r\n",data[7]);
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "Ack:%0d\r\n",data[8]);
    return 0;
}

int CommHeartbeatErr(enum EN_CMD_IDX cmdidx)
{
    static U8 tHbTo=0;
    
    if(CmdTbl[cmdidx].result ==CMD_RSLT_TIMEOUT)
        tHbTo++;
    if(tHbTo==3)
    {
        g_enCommFsm=COMM_FSM_INIT;
        tHbTo=0;
    }
    return 0;
}

int CommBillModeCheck(void *para)
{
    U8 data[MTU]={0};
    int len=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommBillModeCheck Send\r\n");
    
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    *(U16 *)&data[len]=OPP_HTONS(BillModeNumber());
    len+=2;
    return CommSend(BILLMODE_CHK_IDX,AUTO_SEQNO,data,len);
}

int CommBillModeCheckAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM_CHK_Ack:STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM:0x%04x\r\n",OPP_HTONS(*(U16 *)&data[7]));
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM CHK:%d\r\n",data[9]);
    if(data[9]==0)
    {
        g_enCommFsm = COMM_FSM_READY;
        StationStateSet(STA_STATE_IDLE);
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM Chk OK\r\n");
    }
    else
    {
        DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM Chk error\r\n");
    }
    return 0;
}

int CommBillModeCheckErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}

int CommBillModeReq(void *para)
{
    U8 data[MTU]={0};
    int len=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommBillModeReq\r\n");
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    return CommSend(BILLMODE_REQ_IDX,AUTO_SEQNO,data,len);
}

int CommBillModeReqAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;

    
    g_enCommFsm = COMM_FSM_READY;
    StationStateSet(STA_STATE_IDLE);

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "BM_REQ_ACK:STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    len+=STANO_LENGTH;
    bill_model.billModeNo=OPP_NTOHS(*(U16 *)&data[len]);
    len+=2;
    bill_model.SER=*(U32 *)&data[len];
    len+=4;
    bill_model.SSR=*(U32 *)&data[len];
    len+=4;
    bill_model.PER=*(U32 *)&data[len];
    len+=4;
    bill_model.PSR=*(U32 *)&data[len];
    len+=4;
    bill_model.FER=*(U32 *)&data[len];
    len+=4;
    bill_model.FSR=*(U32 *)&data[len];
    len+=4;
    bill_model.VER=*(U32 *)&data[len];
    len+=4;
    bill_model.VSR=*(U32 *)&data[len];
    len+=4;
    bill_model.LCR=data[len++];
    memcpy(bill_model.timerate_map,&data[len],sizeof(bill_model.timerate_map));
    printf("billModeNo:0x%04x\r\n",bill_model.billModeNo);
    printf("SER:%d\r\n",bill_model.SER);
    printf("SSR:%d\r\n",bill_model.SSR);
    printf("PER:%d\r\n",bill_model.PER);
    printf("PSR:%d\r\n",bill_model.PSR);
    printf("FER:%d\r\n",bill_model.FER);
    printf("FSR:%d\r\n",bill_model.FSR);
    printf("VER:%d\r\n",bill_model.VER);
    printf("VSR:%d\r\n",bill_model.VSR);
    printf("LCR:%d\r\n",bill_model.LCR);
    printf("%-10s%-10s\r\n","time","rate");
    for(int i=0;i<sizeof(bill_model.timerate_map);i++)
    {
        printf("%-02d:%-07d%-10d\r\n",(i*30)/60,(i*30)%60,bill_model.timerate_map[i]);
    }
    return 0;
}

int CommBillModeReqErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}

//平台请求桩监控数据
int CommMonitorReq(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommMonitorReq\r\n");
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "GunNum:%d\r\n",data[7]);
    return 0;
}

int CommMakeMonitor(U8 *data, U8 dlen)
{
    int len=0;
    meter_info_t info;
    
    //交易流水号
    memcpy(&data[len],BFNo,BFNO_LENGTH);
    len+=BFNO_LENGTH;
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //len+=MakeTrnNum(&data[len], sizeof(data)-len);
    data[len++]=GunNum;
    //充电状态
    data[len++]=StationStateGet();
    data[len++]=GunIsReturn();
    data[len++]=GunIsPlugin();
    MeterInfoGet(1, &info);
    *(U16 *)&data[len]=info.u32Voltage;
    len+=2;
    *(U16 *)&data[len]=info.u32Current/100;
    len+=2;
    data[len++]=GunTempGet();
    len+=GunCodeGet(&data[len],sizeof(data)-len);
    data[len++]=0;//SOC
    data[len++]=0;//电池组最高温度
    *(U16 *)&data[len]=AcumChgTime();//累计充电时间
    len+=2;
    *(U16 *)&data[len]=AcumRemainTime();//剩余充电时间
    *(U32 *)&data[len]=info.u16Energy/3200;//精确到小数点后四位
    len+=4;
    *(U32 *)&data[len]=0;//计损度数
    len+=4;
    *(U32 *)&data[len]=ChgedMoney;//精确到小数点后四位
    len+=4;
    *(U16 *)&data[len]=HardFault;//硬件故障
    len+=2;
    len+=BmsIdGet(&data[len]);
    return len;
}

int CommMonitorRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data,U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;

    len=CommMakeMonitor(buffer,sizeof(buffer));

    return CommSend(cmdidx,seqno,buffer,len);
}

int CommMonitorRpt(void *para)
{
    U8 buffer[MTU]={0};
    int len=0;
    
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommMonitorRpt\r\n");
    len=CommMakeMonitor(buffer,sizeof(buffer));

    return CommSend(MONITOR_IDX,AUTO_SEQNO,buffer,len);
}


int CommMonitorErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}


int CommActiveStartChgReq(void *para)
{
    U8 data[MTU]={0};
    int len=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommActiveStartChgReq\r\n");
    //桩号
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //抢号
    data[len++]=GunNum;
    //启动方式
    data[len++]=StartChgWay();
    //是否需要密码,0不需要，1需要
    data[len++]=0;
    //账号或卡号
    len+=PhyCardIdGet(&data[len]);
    //密码
    len+=PasswordGet(&data[len]);
    //vin码
    len+=VinGet(&data[len]);
    return CommSend(ACTIVE_START_CHG_IDX,AUTO_SEQNO,data,len);
}

int CommActiveStartChgAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    U8 staNo[16]={0};
    U8 gun;
    U8 logicCardNo[LOGIC_CARDID_LENGTH]={0};
    U32 leftMoney;
    U8 auth,code;
    
    //交易流水号
    memcpy(BFNo,data,BFNO_LENGTH);
    len+=BFNO_LENGTH;
    printf("business flow No:\r\n");
    for(int i=0;i<BFNO_LENGTH;i++)
    {
        printf("%02X", BFNo[i]);
    }
    printf("\r\n");
    
    //桩号
    memcpy(staNo,&data[len],STANO_LENGTH);
    len+=STANO_LENGTH;
    printf("Station No:\r\n");
    for(int i=0;i<STANO_LENGTH;i++)
    {
        printf("%02X", staNo[i]);
    }
    printf("\r\n");
    //枪号
    gun=data[len++];
    printf("GunNo:%d\r\n",gun);
    //逻辑卡号
    memcpy(logicCardNo,&data[len],LOGIC_CARDID_LENGTH);
    printf("logic card no:\r\n");
    for(int i=0;i<LOGIC_CARDID_LENGTH;i++)
    {
        printf("%02X", logicCardNo[i]);
    }
    printf("\r\n");
    len+=LOGIC_CARDID_LENGTH;
    //账户余额
    leftMoney=*(U32 *)&data[len];
    ChgedMoney=leftMoney;
    printf("leftMoney=%d\r\n",leftMoney);
    len+=4;
    //鉴权结果
    auth=data[len++];
    printf("auth=%d\r\n",auth);
    //失败码
    code=data[len++];
    if(auth==0)
    {
        printf("auth err[%d]:%s\r\n",code,stAuthCode[code].desc);
    }
    else if(auth==1)
    {
        printf("auth succ\r\n");
    }
    StationStateSet(STA_STATE_CHG);
    return 0;
}

int CommActiveStartChgErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}

int CommRemoteStartChg(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    U8 staNo[16]={0};
    U8 gun;
    U8 logicCardNo[LOGIC_CARDID_LENGTH]={0};
    U8 phyCardNo[PHY_CARDID_LENGTH]={0};
    U32 leftMoney;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommRemoteStartChg\r\n");
    memcpy(BFNo,data,BFNO_LENGTH);
    len+=BFNO_LENGTH;
    printf("business flow No:\r\n");
    for(int i=0;i<BFNO_LENGTH;i++)
    {
        printf("%02X", BFNo[i]);
    }
    printf("\r\n");
    
    //桩号
    memcpy(staNo,&data[len],STANO_LENGTH);
    len+=STANO_LENGTH;
    printf("Station No:\r\n");
    for(int i=0;i<STANO_LENGTH;i++)
    {
        printf("%02X", staNo[i]);
    }
    printf("\r\n");

    //枪号
    gun=data[len++];
    printf("GunNo:%d\r\n",gun);
    //逻辑卡号
    memcpy(logicCardNo,&data[len],LOGIC_CARDID_LENGTH);
    len+=LOGIC_CARDID_LENGTH;
    printf("logic card no:\r\n");
    for(int i=0;i<LOGIC_CARDID_LENGTH;i++)
    {
        printf("%02X", logicCardNo[i]);
    }
    printf("\r\n");
    //物理卡号
    memcpy(phyCardNo,&data[len],PHY_CARDID_LENGTH);
    len+=PHY_CARDID_LENGTH;
    printf("physical card no:\r\n");
    for(int i=0;i<PHY_CARDID_LENGTH;i++)
    {
        printf("%02X", logicCardNo[i]);
    }
    printf("\r\n");
    
    //账户余额
    leftMoney=*(U32 *)&data[len];
    ChgedMoney=leftMoney;
    printf("leftMoney=%d\r\n",leftMoney);

    if(StationStateGet()==STA_STATE_CHG)
        return 2;
    
    if(HardFault!=0)
        return 3;

    if(g_enCommFsm != COMM_FSM_READY)
        return 4;

    if(!GunIsPlugin())
        return 5;
    
    StationStateSet(STA_STATE_CHG);
    
    return 0;
}

int CommRemoteStartChgRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;

    //交易流水号
    memcpy(&buffer[len],BFNo,BFNO_LENGTH);
    len+=BFNO_LENGTH;
    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //抢号
    buffer[len++]=GunNum;
    if(err==0)
    {
        //启动结果
        buffer[len++]=0x01;//0x00失败 0x01成功
        //失败原因
        buffer[len++]=0x00;
    }
    else
    {
        //启动结果
        buffer[len++]=0x00;//0x00失败 0x01成功
        //失败原因
        buffer[len++]=err;
    }
    
    return CommSend(cmdidx,seqno,buffer,len);
}

int CommRemoteStopChg(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    U8 staNo[16]={0};
    U8 gun;
    
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommRemoteStopChg\r\n");
    
    //桩号
    memcpy(staNo,&data[len],STANO_LENGTH);
    len+=STANO_LENGTH;
    printf("Station No:\r\n");
    for(int i=0;i<STANO_LENGTH;i++)
    {
        printf("%02X", staNo[i]);
    }
    printf("\r\n");

    //枪号
    gun=data[len++];
    printf("GunNo:%d\r\n",gun);

    //ADD YOUR CODE HERE
    //STOP CHG
    //StationStateSet(STA_STATE_IDLE);
    SendStopSignal();
    return 0;
}

int CommRemoteStopChgRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;

    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //抢号
    buffer[len++]=GunNum;
    if(err==0)
    {
        //停止结果
        buffer[len++]=0x01;
        //失败原因
        buffer[len++]=0x00;
    }
    else
    {
        //停止结果
        buffer[len++]=0x00;
        //失败原因
        buffer[len++]=err;
    }
    return CommSend(cmdidx,seqno,buffer,len);
}

//gun_num:1,2
int CommChgRecord(void *para)
{
    U8 data[MTU]={0};
    int len=0;
    CHG_RECORD_PARA_ST* ptr=(CHG_RECORD_PARA_ST*)para;
    U8 gun_num=ptr->gun_num;
    BILL_STATS_ST *stats=ptr->stats;
    
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommChgRecord\r\n");
    //交易流水号
    memcpy(&data[len],BFNo,BFNO_LENGTH);
    len+=BFNO_LENGTH;
    //桩号
    memcpy(&data[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;    
    //抢号
    data[len++]=gun_num;
    //开始时间
    len+=Time2CP56Famat(&stats->time_start, &data[len], sizeof(data)-len);
    //结束时间
    len+=Time2CP56Famat(&stats->time_end, &data[len], sizeof(data)-len);
    //尖单价
    *(U32 *)&data[len]=bill_model.SER;
    len+=4;
    //尖电量
    *(U32 *)&data[len]=stats->SQOE;
    len+=4;
    //计损尖电量
    *(U32 *)&data[len]=0;
    len+=4;
    //尖金额
    *(U32 *)&data[len]=0;
    len+=4;
    //峰单价
    *(U32 *)&data[len]=bill_model.PER;
    len+=4;
    //峰电量
    *(U32 *)&data[len]=stats->PQOE;
    len+=4;
    //计损峰电量
    *(U32 *)&data[len]=0;
    len+=4;
    //峰金额
    *(U32 *)&data[len]=0;
    len+=4;
    //平单价
    *(U32 *)&data[len]=bill_model.FER;
    len+=4;
    //平电量
    *(U32 *)&data[len]=stats->FQOE;
    len+=4;
    //计损平电量
    *(U32 *)&data[len]=0;
    len+=4;
    //平金额
    *(U32 *)&data[len]=0;
    len+=4;
    //谷单价
    *(U32 *)&data[len]=bill_model.VER;
    len+=4;
    //谷电量
    *(U32 *)&data[len]=stats->VQOE;
    len+=4;
    //计损谷电量
    *(U32 *)&data[len]=0;
    len+=4;
    //谷金额
    *(U32 *)&data[len]=0;
    len+=4;
    //电表总起值
    memcpy(&data[len],(U8 *)&stats->elec_start_info.consumption,5);
    len+=5;
    //电表总止值
    memcpy(&data[len],(U8 *)&stats->elec_end_info.consumption,5);
    len+=5;
    //总电量
    *(U32 *)&data[len]=stats->TtlQOE;
    len+=4;
    //计损总电量
    *(U32 *)&data[len]=0;
    len+=4;
    //消费金额
    *(U32 *)&data[len]=0;
    len+=4;
    //电动汽车唯一标识
    len+=VinGet(&data[len]);
    //交易标识
    data[len++]=TransactionID();
    //交易日期、时间
    len+=Time2CP56Famat(&stats->time_end, &data[len], sizeof(data)-len);
    //停止原因
    data[len++]=0x42;
    //物理卡号
    len+=PhyCardIdGet(&data[len]);
    //电池编码
    len+=BmsIdGet(&data[len]);
    return CommSend(CHG_RECORD_IDX,AUTO_SEQNO,data,len);
}

int CommChgRecordAck(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    
    //交易流水号
    printf("business flow no:\r\n");
    for(int i=0;i<BFNO_LENGTH;i++)
    {
        printf("%02X", data[i]);
    }
    printf("\r\n");
    len+=BFNO_LENGTH;

    if(data[len]==0)
    {
        printf("record update success\r\n");
    }
    else
    {
        printf("record update error\r\n");
    }
    return 0;
}

int CommChgRecordErr(enum EN_CMD_IDX cmdidx)
{
    CmdTbl[cmdidx].result=CMD_RSLT_UNEXCE;
    return 0;
}

int CommRemainMoneyUpdate(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    U8 staNo[16]={0};
    PHYCARDID_UN phyCardID;
    U8 gun;
    
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommRemainMoneyUpdate\r\n");
    
    //桩号
    memcpy(staNo,&data[len],STANO_LENGTH);
    len+=STANO_LENGTH;
    printf("Station No:\r\n");
    for(int i=0;i<STANO_LENGTH;i++)
    {
        printf("%02X", staNo[i]);
    }
    printf("\r\n");

    //枪号
    gun=data[len++];
    printf("GunNo:%d\r\n",gun);
    //物理卡号
    memcpy(phyCardID.ID,&data[len],STANO_LENGTH);
    len+=PHY_CARDID_LENGTH;
    printf("Physical CardID:\r\n");
    for(int i=0;i<PHY_CARDID_LENGTH;i++)
    {
        printf("%02X", phyCardID.ID[i]);
    }
    printf("\r\n");

    ChgedMoney=*(U32 *)&data[len];
    len+=4;
    printf("ChgedMoney=%d\r\n",ChgedMoney);
    //ADD YOUR CODE HERE
    //STOP CHG
    
    return 0;
}

int CommRemainMoneyUpdateRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;

    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommRemainMoneyUpdateRsp\r\n");

    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //抢号
    buffer[len++]=GunNum;
    //修改结果
    buffer[len++]=err;
    return CommSend(cmdidx,seqno,buffer,len);
}

int CommTimeSet(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    ST_TIME time;

    printf("time set\r\n");
    //解析
    printf("STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    len+=STANO_LENGTH;
    //设置当前时间
    len+=CP562TimeFamat(&data[len], dlen-len, &time);
    /*time.Sencond=(data[len]|(data[len+1]<<8))/1000;
    len+=2;
    time.Min=data[len++]&0x3F;
    time.Hour=data[len++]&0x1F;
    time.Day=data[len++]&0x1F;
    time.Month=data[len++]&0x0F;
    time.Year=2000+(data[len++]&0x7F);*/
    
    TimeSet(time.Year-2000,time.Month,time.Day,time.Hour,time.Min,time.Sencond,get_zone());
    
    return 0;
}

int CommTimeRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;
    ST_TIME time;
    
    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //设置当前时间
    TimeGet(&time);
    len+=Time2CP56Famat(&time, &data[len], dlen-len);
    /*data[len++]=(time.Sencond*1000)&0x00FF;
    data[len++]=((time.Sencond*1000)&0xFF00)>>8;
    data[len++]=time.Min;
    data[len++]=time.Hour;
    data[len++]=time.Day;
    data[len++]=time.Month;
    data[len++]=data[len++]-2000;*/
    
    return CommSend(cmdidx,seqno,buffer,len);
}

int CommRemoteReboot(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    U8 rebootType;
    
    DEBUG_LOG(DEBUG_MODULE_COMM, DLL_INFO, "CommRemoteReboot\r\n");
    //解析
    printf("STANo:%02x%02x%02x%02x%02x%02x%02x\r\n",
        data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
    len+=STANO_LENGTH;

    rebootType=data[len++];

    //立即重启
    if(rebootType==0x01)
    {
        //OS_REBOOT();
    }
    //空闲执行
    else if(rebootType==0x02)
    {
        
    }
    return rebootType;
}

int CommRemoteRebootRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;
    U8 ret=0;
    
    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    buffer[len++]=0x01;
    ret=CommSend(cmdidx,seqno,buffer,len);
    if(ret!=0)
    {
        printf("reboot CommSend ret=%d\r\n",ret);
    }
    //立即重启
    if(err==0x01)
    {
        OS_REBOOT();
    }
    //空闲执行
    else if(err==0x02)
    {
        
    }
    return 0;
}


int CommQRCodeSet(enum EN_CMD_IDX cmdidx, U16 seqno, U8 *data,U8 dlen)
{
    int len=0;
    int url_length=0;
    char buffer[MTU+1]={0};
    //解析
    printf("GunNo:%d\r\n",data[len++]);
    url_length=data[len++];
    printf("Url length:%d\r\n",url_length);
    //第一个字符是0，跳过字符0
    len++;
    url_length--;
    memcpy(buffer,(char *)&data[len],url_length);
    buffer[url_length]='\0';
    printf("Url:%s\r\n",buffer);
    return 0;
}

int CommQRCodeRsp(enum EN_CMD_IDX cmdidx, U8 err, U16 seqno, U8 *data, U8 dlen)
{
    U8 buffer[MTU]={0};
    int len=0;
    
    //桩号
    memcpy(&buffer[len],STANo,STANO_LENGTH);
    len+=STANO_LENGTH;
    //枪号
    buffer[len++]=GunNum;
    //结果
    if(err==0)
        buffer[len++]=0x01;
    else
        buffer[len++]=0x00;
    
    return CommSend(cmdidx,seqno,buffer,len);
}

CMD_ELEMENT_ST CmdTbl[UNKNOW_IDX]={
    {
    .cmdidx=LOGIN_IDX,
    .scmd=CMD_LOGIN_SND,
    .rcmd=CMD_LOGIN_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommLogin,
    .prsp=NULL,
    .precv=CommLoginAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommLoginErr,
    },
    {
    .cmdidx=HB_IDX,
    .scmd=CMD_HB_SND,
    .rcmd=CMD_HB_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommHeartbeat,
    .prsp=NULL,
    .precv=CommHeartbeatAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommHeartbeatErr,
    },
    {
    .cmdidx=BILLMODE_CHK_IDX,
    .scmd=CMD_BILLMODE_CHK_SND,
    .rcmd=CMD_BILLMODE_CHK_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommBillModeCheck,
    .prsp=NULL,
    .precv=CommBillModeCheckAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommBillModeCheckErr,
    },
    {
    .cmdidx=BILLMODE_REQ_IDX,
    .scmd=CMD_BILLMODE_REQ_SND,
    .rcmd=CMD_BILLMODE_REQ_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommBillModeReq,
    .prsp=NULL,
    .precv=CommBillModeReqAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommBillModeReqErr,
    },
    {
    .cmdidx=MONITOR_IDX,
    .scmd=CMD_MONITOR_RSP,
    .rcmd=CMD_MONITOR_REQ,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=CommMonitorRpt,
    .prsp=CommMonitorRsp,
    .precv=CommMonitorReq,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommBillModeReqErr,
    },
    {
    .cmdidx=ACTIVE_START_CHG_IDX,
    .scmd=CMD_ACTIVE_START_CHG_REQ,
    .rcmd=CMD_ACTIVE_START_CHG_REQ_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommActiveStartChgReq,
    .prsp=NULL,
    .precv=CommActiveStartChgAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommActiveStartChgErr,
    },
    {
    .cmdidx=REMOTE_START_CHG_IDX,
    .scmd=CMD_REMOTE_START_CHG_SET_RSP,
    .rcmd=CMD_REMOTE_START_CHG_SET,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommRemoteStartChgRsp,
    .precv=CommRemoteStartChg,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    },
    {
    .cmdidx=REMOTE_STOP_CHG_IDX,
    .scmd=CMD_REMOTE_STOP_CHG_SET_RSP,
    .rcmd=CMD_REMOTE_STOP_CHG_SET,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommRemoteStopChgRsp,
    .precv=CommRemoteStopChg,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    },
    {
    .cmdidx=CHG_RECORD_IDX,
    .scmd=CMD_CHG_RECORD_SND,
    .rcmd=CMD_CHG_RECORD_ACK,
    .stick=0,
    .rtick=0,
    .timeout=10000,
    .psend=CommChgRecord,
    .prsp=NULL,
    .precv=CommChgRecordAck,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=CommChgRecordErr,
    },
    {
    .cmdidx=REMAIN_MONEY_UPDATE_IDX,
    .scmd=CMD_REMAIN_MONEY_UPDATE_RSP,
    .rcmd=CMD_REMAIN_MONEY_UPDATE,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommRemainMoneyUpdateRsp,
    .precv=CommRemainMoneyUpdate,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    },
    {
    .cmdidx=TIME_IDX,
    .scmd=CMD_TIME_SET_RSP,
    .rcmd=CMD_TIME_SET,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommTimeRsp,
    .precv=CommTimeSet,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    },
    {
    .cmdidx=REMOTE_REBOOT_IDX,
    .scmd=CMD_REMOTE_REBOOT_RSP,
    .rcmd=CMD_REMOTE_REBOOT,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommTimeRsp,
    .precv=CommTimeSet,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    },
    {
    .cmdidx=QRCODE_IDX,
    .scmd=CMD_QRCODE_SET_RSP,
    .rcmd=CMD_QRCODE_SET,
    .stick=0,
    .rtick=0,
    .timeout=INVALID_TO,
    .psend=NULL,
    .prsp=CommQRCodeRsp,
    .precv=CommQRCodeSet,
    .result=CMD_RSLT_UNEXCE,
    .code=0,
    .eAction=NULL,
    }
};
#warning "Charge Station Command Above"


enum EN_COMM_FSM CommFsmGet(void)
{
    return g_enCommFsm;
}

void CommCmdTblReset(void)
{
    for(int i=0;i<sizeof(CmdTbl)/sizeof(CMD_ELEMENT_ST);i++)
    {
        CmdTbl[i].result = CMD_RSLT_UNEXCE;
        CmdTbl[i].code = 0;
        CmdTbl[i].stick = 0;
        CmdTbl[i].rtick = 0;
    }
}

void CommHBRegular(int timeout,int (*pfunc)(void *))
{
    static U32 tick = 0;

    if(OppTickCountGet() - tick > timeout){
        pfunc(NULL);
        tick = OppTickCountGet();
    }
}

void CommMonitorRegular(int timeout,int (*pfunc)(void *))
{
    static U32 tick = 0;

    if(OppTickCountGet() - tick > timeout){
        pfunc(NULL);
        tick = OppTickCountGet();
    }
}

void CommCmdTimeout(void)
{
    for(int i=0;i<sizeof(CmdTbl)/sizeof(CMD_ELEMENT_ST);i++)
    {
        //0不做超时处理
        if(CmdTbl[i].timeout == INVALID_TO)
            continue;
        if(CmdTbl[i].result == CMD_RSLT_WAIT)
        {
            if(OppTickCountGet() - CmdTbl[i].stick > CmdTbl[i].timeout)
            {
                CmdTbl[i].result=CMD_RSLT_TIMEOUT;
            }
        }
    }
}
void CommCmdAbnormal(void)
{
    for(int i=0;i<sizeof(CmdTbl)/sizeof(CMD_ELEMENT_ST);i++)
    {
        if(CmdTbl[i].result == CMD_RSLT_TIMEOUT||CmdTbl[i].result == CMD_RSLT_ERROR)
        {
            CmdTbl[i].eAction((enum EN_CMD_IDX)i);
        }
    }
}

//充电桩状态变化上报监控数据
void MonitorChgRpt(void)
{
    static enum EN_STA_STATE lastState=STA_STATE_OFFLINE;
    static U8 lastGunPlugin=0;
    static U16 lastHardFault=0;
    U8 report=0;
    
    if(lastState!=StationStateGet())
    {
        lastState=StationStateGet();
        report=1;
    }
    if(lastGunPlugin!=GunIsPlugin())
    {
        lastGunPlugin=GunIsPlugin();
        report=1;
    }
    if(lastHardFault!=HardFault)
    {
        lastHardFault=HardFault;
        report=1;
    }
    //上报监控数据
    if(report==1)
        CommMonitorRpt(NULL);
}

int CommLoop(void)
{
    int err;
    int sErrCnt=0;
    static EN_EC600S_CTX ctx=CTX_INIT;

    if(ctx != Ec600sCtxGet())
    {
        ctx=Ec600sCtxGet();
        if(ctx==CTX_READY)
            g_enCommFsm=COMM_FSM_INIT;
    }
    
    if(ctx!=CTX_READY)
        return 0;
    
    switch (g_enCommFsm)
    {
        case COMM_FSM_INIT:
            printf("comunication inition...\r\n");
            CommCmdTblReset();
            err=CommSockInit();
            if(err == 0)
            {
                g_enCommFsm = COMM_FSM_LOGON;
            }
            else
            {
                if(sErrCnt++ > 10)
                {
                    g_enCommFsm = COMM_FSM_ABNORMAL;
                }
            }
            break;
        case COMM_FSM_LOGON:
            if(CmdTbl[LOGIN_IDX].result==CMD_RSLT_UNEXCE)
            {
                err=CmdTbl[LOGIN_IDX].psend(NULL);
            }
            if(CmdTbl[LOGIN_IDX].result==CMD_RSLT_SUCC && CmdTbl[BILLMODE_CHK_IDX].result==CMD_RSLT_UNEXCE)
            {
                err=CmdTbl[BILLMODE_CHK_IDX].psend(NULL);
            }

            if(CmdTbl[BILLMODE_CHK_IDX].result==CMD_RSLT_SUCC && CmdTbl[BILLMODE_REQ_IDX].result==CMD_RSLT_UNEXCE)
            {
                err=CmdTbl[BILLMODE_REQ_IDX].psend(NULL);
            }
            CommReceive();
            break;
        case COMM_FSM_READY:
            MonitorChgRpt();
            CommHBRegular(10000,CommHeartbeat);
            CommMonitorRegular(15000,CommMonitorRpt);
            CommReceive();
            break;
        case COMM_FSM_ABNORMAL:
            Ec600sClose(sock);
            Ec600sReset(EC600S_RST_CMD);
            g_enCommFsm = COMM_FSM_INIT;
            break;
        default:
            break;
    }
    CommCmdTimeout();
    CommCmdAbnormal();
    return 0;
}







